package com.easylinkin.linkappapi.listener;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.easylinkin.linkappapi.alarm.entity.Alarm;
import com.easylinkin.linkappapi.alarm.mapper.AlarmMapper;
import com.easylinkin.linkappapi.device.entity.Device;
import com.easylinkin.linkappapi.security.constant.LinkappUserConstant;
import com.easylinkin.linkappapi.security.entity.LinkappUser;
import com.easylinkin.linkappapi.security.mapper.LinkappUserMapper;
import com.easylinkin.linkappapi.space.entity.LinkappSpace;
import com.easylinkin.linkappapi.space.mapper.LinkappSpaceMapper;
import org.apache.commons.lang3.ObjectUtils;
import org.redisson.api.RTopic;
import org.redisson.api.RedissonClient;
import org.redisson.codec.SerializationCodec;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.websocket.OnClose;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.stream.Collectors;

/**
 * @program: linkapp-group
 * @description: 设备告警
 * @author: chenkaixuan
 * @create: 2021-07-21 15:58
 */
@ServerEndpoint("/alarmListen/{tenantId}/{userId}")
@Component
public class DeviceAlarmListener  extends Listener{
    @Value("${linkapp.openReceiving:true}")
    private Boolean openReceiving;
    private static final Logger LOGGER = LoggerFactory.getLogger(DeviceAlarmListener.class);
    private static AlarmMapper alarmMapper;
    private static LinkappUserMapper linkappUserMapper;
    private static LinkappSpaceMapper linkappSpaceMapper;
//    private static RedisUtil redisUtil;
    private static CopyOnWriteArraySet<Listener> webSocketSet = new CopyOnWriteArraySet<>();

    @Resource
    private RedissonClient redisson;
    public static String WS_DEVICEALARM_LISTEN = "WS_DEVICEALARM_LISTEN";
    private RTopic topic;

    @Override
    @OnOpen
    public void onOpen(Session session, @PathParam("tenantId") String tenantId, @PathParam("userId") String userId) {
        init(session, tenantId, userId);
        // 加入set中
        webSocketSet.add(this);
        sendInitNotice();
    }

    /***
     * 初始消息推送
     */
    private void sendInitNotice(){
        List<Alarm> alarmList=getMessage(null,this.getTenantId(),this.getUserId());
        if(alarmList == null || alarmList.size()<=0){
            return;
        }
        String jsonText=JSON.toJSONString(alarmList);
        this.sendMessage(jsonText);
    }

    /**
     * 连接关闭调用的方法
     */
    @Override
    @OnClose
    public void onClose() {
        LOGGER.info("通知关闭连接,用户id:{}", getUserId());
        // 从set中删除
        webSocketSet.remove(this);
    }

    /**
     * 开启监听
     */
    @PostConstruct
    void openReceiving() {
        if (!openReceiving) {
            return;
        }
        topic = redisson.getTopic(WS_DEVICEALARM_LISTEN, new SerializationCodec());
        LOGGER.info("监听ws成功：{}", topic);
        topic.addListener(Alarm.class, (charSequence, alarm) -> {
            send(alarm);
        });
    }

    public void sendNotice(Alarm alarm) {
//        redis 发广播
        try {
            topic.publish(alarm);
        } catch (Exception e) {
            LOGGER.error("sendNotice失败：", e);
        }

//        String key = WS_DEVICEALARM_LISTEN + UUID.randomUUID();
//        redisUtil.set(key+ "_param", alarm, 15);
//        //        10毫秒过期
//        redisUtil.setExpiredMilliseconds(key, "", 10);
    }

    public void send(Alarm alarm) {
        if(StringUtils.isEmpty(alarm) ||  StringUtils.isEmpty(alarm.getId())){
            return;
        }
        for (Listener listener : webSocketSet) {
            if(alarm.getTenantId() == null || !alarm.getTenantId().equals(listener.getTenantId())){
                continue;
            }
            List<Alarm> alarmList=getMessage(alarm,listener.getTenantId(),listener.getUserId());
            if(alarmList == null || alarmList.size()<=0){
                continue;
            }
            listener.sendMessage(JSON.toJSONString(alarmList));
        }
    }

    private List<Alarm> getMessage(Alarm alarm,String tenantId,String userId){
        if(StringUtils.isEmpty(tenantId) || StringUtils.isEmpty(userId)){
            return null;
        }
        Page page=new Page(0,15);
        if(alarm == null){
            alarm=new Alarm();
        }
        if(alarm.getDevice() == null){
            alarm.setDevice(new Device());
        }
        alarm.setTenantId(tenantId);
        alarm.setStatus(1);
        IPage<Alarm> alarmIPage=alarmMapper.getAlarms(page,alarm,getCurrentUserSpaceIds(userId));
        return alarmIPage.getRecords();
    }

    /***
     * 获取空间信息
     * @param userId
     * @return
     */
    private List<String> getCurrentUserSpaceIds(String userId){
        List<LinkappSpace> spaces = getCurrentUserSpace(userId);
        if (ObjectUtils.isEmpty(spaces)) {
            return new ArrayList<>();
        }
        return spaces.stream().map(LinkappSpace::getId).collect(Collectors.toList());
    }
    private List<LinkappSpace> getCurrentUserSpace(String userId){
        LinkappUser currentUser = linkappUserMapper.selectById(userId);
        if(LinkappUserConstant.ADMIN_TYPE.equals(currentUser.getType())){
            return linkappSpaceMapper.selectLinkappSpaceList(new LinkappSpace());
        }else{
            return linkappUserMapper.selectCurrentUserSpace(currentUser.getId());
        }
    }

    @Resource
    public  void setAlarmMapper(AlarmMapper alarmMapper) {
        DeviceAlarmListener.alarmMapper = alarmMapper;
    }
    @Resource
    public  void setLinkappUserMapper(LinkappUserMapper linkappUserMapper) {
        DeviceAlarmListener.linkappUserMapper = linkappUserMapper;
    }
    @Resource
    public  void setLinkappSpaceMapper(LinkappSpaceMapper linkappSpaceMapper) {
        DeviceAlarmListener.linkappSpaceMapper = linkappSpaceMapper;
    }
//    @Resource
//    public  void setRedisUtil(RedisUtil redisUtil) {
//        DeviceAlarmListener.redisUtil = redisUtil;
//    }
}
